package edu.hitsz.application;

import edu.hitsz.RankTable;
import edu.hitsz.aircraft.*;
import edu.hitsz.bullet.BaseBullet;
import edu.hitsz.basic.AbstractFlyingObject;
import edu.hitsz.prop.*;
import edu.hitsz.rank.RankDaoImpl;
import edu.hitsz.rank.RankInfo;
import edu.hitsz.shoot.*;
import edu.hitsz.shoot.ShootContext;
import org.apache.commons.lang3.concurrent.BasicThreadFactory;

import javax.swing.*;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.List;
import java.util.concurrent.*;

import static edu.hitsz.aircraft.HeroAircraft._heroAircraft;

/**
 * 游戏主面板，游戏启动
 *
 * @author hitsz
 */
public class SimpleGame extends Game {

    //线程判断标志
    public static int if_shoot = 0;
    public static int if_music = 1;

    private int backGroundTop = 0;

    private BufferedImage back_image;

    /**
     * Scheduled 线程池，用于任务调度
     */
    private final ScheduledExecutorService executorService;

    /**
     * 时间间隔(ms)，控制刷新频率
     */
    private int timeInterval = 40;

    private int num_boss = 1;
    private final HeroAircraft heroAircraft;
    private final List<MobEnemy> enemyAircrafts;
    private final List<Prop> props;
    private final List<BaseBullet> heroBullets;
    private final List<BaseBullet> enemyBullets;
    private BombEffect bombEffect = new BombEffect();

    /**
     * Enemy工厂
     */
    private final ElitePlusFactory elitePlusFactory = new ElitePlusFactory();
    private final BossFactory bossFactory = new BossFactory();

    /**
     * 子弹工厂
     */
    private int boss_bullets = 3;

    private final PropFactory blood_factory = new BloodFactory();
    private final PropFactory bullet_factory = new BulletFactory();
    private final PropFactory bullet_plus_factory = new BulletPlusFactory();
    private final PropFactory bomb_factory = new BombFactory();

    /**
     * 发射操作上下文
     */
    private ShootContext shootcontext = new ShootContext(new DirectShoot(_heroAircraft.getHeroAircraft(), -1));

    /**
     * 屏幕中出现的敌机最大数量
     */
    private int enemyMaxNumber = 5;

    /**
     * 当前得分
     */
    private int score = 0;
    /**
     * 当前时刻
     */
    private int time = 0;

    /**
     * 周期（ms)
     * 指示子弹的发射、敌机的产生频率
     */
    private int cycleDuration = 600;
    private int cycleTime = 0;

    /**
     * 游戏结束标志
     */
    private boolean gameOverFlag = false;

    public SimpleGame(int bg) {
        super(bg);
        new MusicThread("src/bgm.wav", 1).start();
        heroAircraft = _heroAircraft.getHeroAircraft();
        enemyAircrafts = new LinkedList<>();
        heroBullets = new LinkedList<>();
        enemyBullets = new LinkedList<>();
        props = new LinkedList<>();

        if(bg == 0)
            back_image = ImageManager.BACKGROUND_IMAGE;
        else if (bg == 1) {
            back_image = ImageManager.BACKGROUND_IMAGE2;
        } else{
            back_image = ImageManager.BACKGROUND_IMAGE3;
        }

        /**
         * Scheduled 线程池，用于定时任务调度
         * 关于alibaba code guide：可命名的 ThreadFactory 一般需要第三方包
         * apache 第三方库： org.apache.commons.lang3.concurrent.BasicThreadFactory
         */
        this.executorService = new ScheduledThreadPoolExecutor(1,
                new BasicThreadFactory.Builder().namingPattern("game-action-%d").daemon(true).build());

        //启动英雄机鼠标监听
        new HeroController(this, heroAircraft);

    }

    /**
     * 游戏启动入口，执行游戏逻辑
     */
    public void action() {

        // 定时任务：绘制、对象产生、碰撞判定、击毁及结束判定
        Runnable task = () -> {

            time += timeInterval;


            // 周期性执行（控制频率）
            if (timeCountAndNewCycleJudge()) {
                System.out.println(time);
                // 新敌机产生
                if(score >= 200 * num_boss)
                {
                    if_music = 2;
                    new MusicThread("src/videos/bgm_boss.wav", 2).start();
                    num_boss += 1;
                    enemyAircrafts.add(bossFactory.CreateEnemy(
                            (int) (Math.random() * (Main.WINDOW_WIDTH - ImageManager.MOB_ENEMY_IMAGE.getWidth())),
                            (int) (Math.random() * Main.WINDOW_HEIGHT * 0.05 + 100),
                            3,
                            0,
                            500
                    ));
                    bombEffect.addEnemy(enemyAircrafts.get(enemyAircrafts.size() - 1));
                }

                if (enemyAircrafts.size() < enemyMaxNumber) {

                    if((int)(Math.random() * 10) % 5 == 0){
                        enemyAircrafts.add(elitePlusFactory.CreateEnemy(
                                (int) (Math.random() * (Main.WINDOW_WIDTH - ImageManager.MOB_ENEMY_IMAGE.getWidth())),
                                (int) (Math.random() * Main.WINDOW_HEIGHT * 0.05),
                                3,
                                10,
                                30
                        ));
                    }else if((int)(Math.random() * 10) % 5 <= 2) {
                        enemyAircrafts.add(new EliteEnemy(
                                (int) (Math.random() * (Main.WINDOW_WIDTH - ImageManager.MOB_ENEMY_IMAGE.getWidth())),
                                (int) (Math.random() * Main.WINDOW_HEIGHT * 0.05),
                                3,
                                10,
                                30
                        ));

                    }else {
                        enemyAircrafts.add(new MobEnemy(
                                (int) (Math.random() * (Main.WINDOW_WIDTH - ImageManager.MOB_ENEMY_IMAGE.getWidth())),
                                (int) (Math.random() * Main.WINDOW_HEIGHT * 0.05),
                                0,
                                10,
                                30
                        ));
                    }
                    bombEffect.addEnemy(enemyAircrafts.get(enemyAircrafts.size() - 1));
                }
                // 飞机射出子弹
                shootAction();
            }

            // 子弹移动
            bulletsMoveAction();

            // 飞机移动
            aircraftsMoveAction();

            // 撞击检测
            crashCheckAction();

            // 后处理
            postProcessAction();

            //每个时刻重绘界面
            repaint();

            // 游戏结束检查英雄机是否存活
            if (heroAircraft.getHp() <= 0) {
                new ShortMusicThread("src/videos/game_over.wav").start();
                if_music = 0;
                if_shoot = 0;

                File file = new File("src/edu/hitsz/application/rank.txt");
                try {
                    RankDaoImpl rankDao = new RankDaoImpl(file);
                    Date date = new Date();
                    SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss");
                    String time = df.format(date);

                    String user_name = JOptionPane.showInputDialog(null, "请输入用户名", "test_user");

                    RankInfo rankInfo = new RankInfo(user_name, score, time);
                    rankDao.addRankInfo(rankInfo);
                    rankDao.sortRankInfoList();
                    rankDao.printRankInfoList();
                    rankDao.saveRankInfoList("src/edu/hitsz/application/rank.txt");

                    JFrame frame = new JFrame("RankTable");
                    frame.setContentPane(new RankTable(rankDao).getMainPanal());
                    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                    frame.pack();
                    frame.setVisible(true);

                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
                // 游戏结束
                executorService.shutdown();
                gameOverFlag = true;
                System.out.println("Game Over!");
            }

        };

        /**
         * 以固定延迟时间进行执行
         * 本次任务执行完成后，需要延迟设定的延迟时间，才会执行新的任务
         */
        executorService.scheduleWithFixedDelay(task, timeInterval, timeInterval, TimeUnit.MILLISECONDS);

    }

    //***********************
    //      Action 各部分
    //***********************

    boolean timeCountAndNewCycleJudge() {
        cycleTime += timeInterval;
        if (cycleTime >= cycleDuration && cycleTime - timeInterval < cycleTime) {
            // 跨越到新的周期
            cycleTime %= cycleDuration;
            return true;
        } else {
            return false;
        }
    }

    private void shootAction() {
        // TODO 敌机射击
        for (AbstractAircraft enemyAircraft : enemyAircrafts) {
            if (enemyAircraft instanceof Boss) {
                shootcontext.setStrategy(new CircleShoot(enemyAircraft, 1));
                if (boss_bullets == 3) {
                    enemyBullets.addAll(shootcontext.execiteStrategy());
                    boss_bullets = 0;
                }
            } else {
                shootcontext.setStrategy(new DiffuseShoot(enemyAircraft, 1));
                enemyBullets.addAll(enemyAircraft.shoot());
            }
        }
        boss_bullets += 1;
        // 英雄射击
        if(heroAircraft.shoot_type == 0)
            shootcontext.setStrategy(new DirectShoot(heroAircraft, -1));
        else if(heroAircraft.shoot_type == 1)
            shootcontext.setStrategy(new CircleShoot(heroAircraft, -1));
        else if(heroAircraft.shoot_type == 2)
            shootcontext.setStrategy(new DiffuseShoot(heroAircraft, -1));

        heroBullets.addAll(shootcontext.execiteStrategy());
        new ShortMusicThread("src/videos/bullet.wav").start();
    }

    private void bulletsMoveAction() {
        for (BaseBullet bullet : heroBullets) {
            bullet.forward();
        }
        for (BaseBullet bullet : enemyBullets) {
            bullet.forward();
        }
    }

    private void aircraftsMoveAction() {
        for (AbstractAircraft enemyAircraft : enemyAircrafts) {
            enemyAircraft.forward();
        }
        for (AbstractFlyingObject prop : props){
            prop.forward();
        }
    }


    /**
     * 碰撞检测：
     * 1. 敌机攻击英雄
     * 2. 英雄攻击/撞击敌机
     * 3. 英雄获得补给
     */
    private void crashCheckAction() {
        // TODO 敌机子弹攻击英雄
        for (BaseBullet bullet : enemyBullets) {
            if (bullet.notValid()) {
                continue;
            }

            if(heroAircraft.crash(bullet)){
                heroAircraft.decreaseHp(bullet.getPower());
                bullet.vanish();
            }
        }

        // 英雄子弹攻击敌机
        for (BaseBullet bullet : heroBullets) {
            if (bullet.notValid()) {
                continue;
            }
            for (AbstractAircraft enemyAircraft : enemyAircrafts) {
                if (enemyAircraft.notValid()) {
                    // 已被其他子弹击毁的敌机，不再检测
                    // 避免多个子弹重复击毁同一敌机的判定
                    continue;
                }
                if (enemyAircraft.crash(bullet)) {
                    // 敌机撞击到英雄机子弹
                    // 敌机损失一定生命值
                    new ShortMusicThread("src/videos/bullet_hit.wav").start();
                    enemyAircraft.decreaseHp(bullet.getPower());
                    bullet.vanish();
                    if (enemyAircraft.notValid()) {
                        // TODO 获得分数，产生道具补给
                        score += 10;
                        if(enemyAircraft instanceof EliteEnemy)
                        {
                            int type = (int)(Math.random() * 13) % 13;
                            if(type < 3) {
                                props.add(blood_factory.CreateProp(enemyAircraft.getLocationX(),
                                        enemyAircraft.getLocationY(),
                                        0,
                                        10));
                            }
                            else if(type < 6) {
                                props.add(bullet_plus_factory.CreateProp(enemyAircraft.getLocationX(),
                                        enemyAircraft.getLocationY(),
                                        0,
                                        10));
                            }else if(type < 9) {
                                props.add(bullet_factory.CreateProp(enemyAircraft.getLocationX(),
                                        enemyAircraft.getLocationY(),
                                        0,
                                        10));
                            }else if(type < 12){
                                props.add(bomb_factory.CreateProp(enemyAircraft.getLocationX(),
                                        enemyAircraft.getLocationY(),
                                        0,
                                        10));
                            }
                        }
                        if(enemyAircraft instanceof Boss)
                        {
                            if_music = 1;
                            new MusicThread("src/videos/bgm.wav", 1).start();
                            for(int i = -1; i < 2; i++)
                            {
                                int type = (int)(Math.random() * 9) % 10;
                                if(type < 3) {
                                    props.add(blood_factory.CreateProp(enemyAircraft.getLocationX(),
                                            enemyAircraft.getLocationY(),
                                            i * 5,
                                            10));
                                }
                                else if(type < 6) {
                                    props.add(bullet_plus_factory.CreateProp(enemyAircraft.getLocationX(),
                                            enemyAircraft.getLocationY(),
                                            i * 5,
                                            10));
                                }else if(type < 9) {
                                    props.add(bullet_factory.CreateProp(enemyAircraft.getLocationX(),
                                            enemyAircraft.getLocationY(),
                                            i * 5,
                                            10));
                                }
                            }
                        }
                    }
                }
                // 英雄机 与 敌机 相撞，均损毁
                if (enemyAircraft.crash(heroAircraft) || heroAircraft.crash(enemyAircraft)) {
                    enemyAircraft.vanish();
                    heroAircraft.decreaseHp(Integer.MAX_VALUE);
                }
            }
        }

        for(Prop prop : props){
            if(heroAircraft.crash(prop) || prop.crash(heroAircraft)){
                prop.vanish();
                if(prop instanceof PropBomb)
                    ((PropBomb) prop).effect(bombEffect);
                else
                    prop.effect(heroAircraft);
                new ShortMusicThread("src/videos/get_supply.wav").start();
            }
        }


    }

    /**
     * 后处理：
     * 1. 删除无效的子弹
     * 2. 删除无效的敌机
     * <p>
     * 无效的原因可能是撞击或者飞出边界
     */
    private void postProcessAction() {
        enemyBullets.removeIf(AbstractFlyingObject::notValid);
        heroBullets.removeIf(AbstractFlyingObject::notValid);
        enemyAircrafts.removeIf(AbstractFlyingObject::notValid);
        bombEffect.remove_vanish();
        props.removeIf(AbstractFlyingObject::notValid);
    }


    //***********************
    //      Paint 各部分
    //***********************

    /**
     * 重写paint方法
     * 通过重复调用paint方法，实现游戏动画
     *
     * @param  g
     */
    @Override
    public void paint(Graphics g) {
        super.paint(g);

        // 绘制背景,图片滚动
        g.drawImage(back_image, 0, this.backGroundTop - Main.WINDOW_HEIGHT, null);
        g.drawImage(back_image, 0, this.backGroundTop, null);
        this.backGroundTop += 1;
        if (this.backGroundTop == Main.WINDOW_HEIGHT) {
            this.backGroundTop = 0;
        }

        // 先绘制子弹，后绘制飞机
        // 这样子弹显示在飞机的下层
        paintImageWithPositionRevised(g, enemyBullets);
        paintImageWithPositionRevised(g, heroBullets);

        paintImageWithPositionRevised(g, enemyAircrafts);
        paintImageWithPositionRevised(g, props);

        g.drawImage(ImageManager.HERO_IMAGE, heroAircraft.getLocationX() - ImageManager.HERO_IMAGE.getWidth() / 2,
                heroAircraft.getLocationY() - ImageManager.HERO_IMAGE.getHeight() / 2, null);

        //绘制得分和生命值
        paintScoreAndLife(g);

    }

    private void paintImageWithPositionRevised(Graphics g, List<? extends AbstractFlyingObject> objects) {
        if (objects.size() == 0) {
            return;
        }

        for (AbstractFlyingObject object : objects) {
            BufferedImage image = object.getImage();
            assert image != null : objects.getClass().getName() + " has no image! ";
            g.drawImage(image, object.getLocationX() - image.getWidth() / 2,
                    object.getLocationY() - image.getHeight() / 2, null);
        }
    }

    private void paintScoreAndLife(Graphics g) {
        int x = 10;
        int y = 25;
        g.setColor(new Color(16711680));
        g.setFont(new Font("SansSerif", Font.BOLD, 22));
        g.drawString("SCORE:" + this.score, x, y);
        y = y + 20;
        g.drawString("LIFE:" + this.heroAircraft.getHp(), x, y);
    }


}
